package com.yss.exams;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * 可以在此类中增加辅助方法。
 */
public final class TreeUtil {
  private TreeUtil() {
  }

    /**
     *主要方便操作特意添加
     */
  private static List<Optional<String>> list = new ArrayList<>();
    /**
     * 栈信息，根据TreeNode->依次存放各个层次的数据
     */
  private static Stack<String> stack = new Stack<>();
    /**
     * 中间过渡
     */
  private static TreeNode node;

  /**
   * 根据规则将String转换为树（森林），假设text始终合法（非空且合乎规则）。
   */
  public static List<TreeNode> stringToTree(final String text) {
    List<TreeNode> treeNodeList = new ArrayList<>();
    String[] allLine =text.split("\n");
    String[] temp=null;
    TreeNode node = null;
    for (int i = 0; i < allLine.length; i++) {
      temp=allLine[i].split("\t");
      if(temp.length==1){
        node= new TreeNode(temp[temp.length-1]);
        treeNodeList.add(node);
      }else{
        //查找父节点,并添加到子节点上
        findParentNode(node,temp.length-1).getChildren().add(new TreeNode(temp[temp.length-1]));
      }
    }
    return treeNodeList;
  }

  /**
   * 根据规则将树（森林）转为String，假设tree始终非空。
   */
  public static String treeToString(List<TreeNode> tree) {
    StringBuilder sb = new StringBuilder();
    buildStringByList(tree,0,sb);
    return sb.toString();
  }

  /**
   * 查找树（森林）中所有满足断言的节点的路径，假设tree始终非空。
   * 这个是不是每个树上所有节点都放在String[] ,多个树放在List-->List<String[]>
   */
  public static List<String[]> findAllPaths(List<TreeNode> tree, Predicate<Optional<String>> action) {
    //1.将树的对象转成路径List<String[]>
    list.clear();
     changeListToArray(tree,0);
     //将list转成List<String[]>
     List<Optional<String>> temp;//每个树
     List<List<Optional<String>>> treeList = new ArrayList<>();

     //2. List<Optional<String>>  类型转成 树->List<Optional<String>>
    for (int i=0;i<tree.size();i++){
        temp= new ArrayList<>();
         for(int j=0;j<list.size();j++){
          if(list.get(j).get().startsWith(tree.get(i).getData().get())){
            temp.add(list.get(j));
          }
        }
         List<Optional<String>> datadata=temp.stream().filter(action).collect(Collectors.toList());
         treeList.add(datadata);
     }
    //3.将 List<Optional<String>> -->转String[]
    List<String[]> data = new ArrayList<>(treeList.size());
    String[] arrData;
    for (int i = 0; i < treeList.size(); i++) {
       arrData = new String[treeList.get(i).size()];
       for (int j=0;j<treeList.get(i).size();j++){
         arrData[j]=treeList.get(i).get(j).get();
       }
       data.add(arrData);
    }

    return  data;
  }

    /**
     *     将TreeNode的所有的路径生成
     */
  public static void changeListToArray(List<TreeNode> tree,int line){
      for (int i=0;i<tree.size();i++) {
         node = tree.get(i);
         stack.push(node.getData().get());
         if(node.getChildren().size()==0){
           buildStringPath(line);
           stack.pop();
         }else{
           changeListToArray(node.getChildren(),line+1);
         }
          //父节点为空的情况
        if(i==tree.size()-1 && !stack.empty()){
          stack.pop();
        }
      }
  }

  private static void buildStringPath(int line){
    StringBuilder sb = new StringBuilder();
    for (int i=0;i<=line;i++){
      sb.append(buildTab(i)).append(stack.get(i)).append("\n");
    }
     list.add(Optional.of(sb.toString()));
  }

    /***
     * 根据当前节点所在头节点,子节点层数，
     * @param node
     * @param index
     * @return
     */
  private static TreeNode findParentNode(TreeNode node,int index){
    if(index == 1){
      return node;
    }
     for(int i=0;i<index-1;i++) {
       //关键是这一步，后面每次添加的都是按照同等级的最后一个，
       node = node.getChildren().get(node.getChildren().size() - 1);
     }
    return node;
  }

  private static void buildStringByList(List<TreeNode> tree,int line,StringBuilder sb){
    if(tree == null || tree.size()==0){
       return;
    }else{
      for (TreeNode node:tree) {
        sb.append(buildTab(line)).append(node.getData().get()).append("\n");
          //递归调用
        buildStringByList(node.getChildren(),line + 1, sb);
      }
    }
  }

  private static String buildTab(int line){
    if (line == 0){
      return "";
    }
    StringBuilder sb = new StringBuilder();
    for(int i=0;i<line;i++){
      sb.append("\t");
    }
    return sb.toString();
  }

  public static void main(String[] args) {
    String test="1\n\t1.1\n\t\t1.1.1\n\t\t\t1.1.1.1\n\t\t\t1.1.1.2\n"+
            "\t\t1.1.2\n\t\t\t1.1.2.1\n\t\t\t1.1.2.2\n\t1.2\n\t\t1.2.1\n\t\t1.2.2\n"
            +"2\n\t2.1\n\t\t2.1.1\n\t\t2.1.2\n";
    List<TreeNode> treeNodeList =stringToTree(test);
    System.out.println("===================");
    System.out.println(treeToString(treeNodeList));
    changeListToArray(treeNodeList,0);
    System.out.println("=============");

    List<String[]>  data= findAllPaths(treeNodeList,str->{
      if(str.get().startsWith("1\n\t1.1\n\t\t1.1.1\n")){
        return true;
      }

      return false;
    });

    System.out.println("=============");
    data.stream().forEach(strArr-> Arrays.stream(strArr).forEach(System.out::println));
  }
}
